package com.ibm.crl.sb.thread.typicalexam.writereader;

/**
 * 读者写者问题
 * 
 * @author soft
 * 
 */
public class WriterReader {
	public static void main(String[] args) {

		CubbyHole db = new CubbyHole();// 缓冲区
		Reader r1 = new Reader(1, db);// 读者
		Reader r2 = new Reader(2, db);
		Reader r3 = new Reader(3, db);
		Reader r4 = new Reader(4, db);
		Writer w1 = new Writer(1, db);// 写者
		Writer w2 = new Writer(2, db);

		r1.start();
		r2.start();
		r3.start();
		w1.start();
		r4.start();
		w2.start();

	}
}

class CubbyHole {
	private int readerCount;// 读者数
	private int writerCount;// 写者数
	private boolean dbReading;// 读信号量
	private boolean dbWriting;// 写信号量

	public CubbyHole() {
		readerCount = 0;
		writerCount = 0;
		dbReading = false;
		dbWriting = false;

	}

	public static void napping() {// 线程睡眠，不消耗CPU资源

		try {
			Thread.sleep((int) (Math.random() * 4000));
		} catch (Exception e) {

		}
	}

	public synchronized int startRead() {// 开始读
		while (writerCount > 0) {
			try {
				System.out.println("reader is waiting");
				wait();// 等待写者发出notify
			} catch (Exception e) {
			}
		}
		++readerCount;
		if (readerCount == 1) {
			dbReading = true;
		}
		return readerCount;
	}

	public synchronized int endReading() {// 结束读
		--readerCount;
		if (readerCount == 0) {
			dbReading = false;
		}
		notifyAll();
		System.out.println("one reader is done reading. Count=" + readerCount);
		return readerCount;
	}

	public synchronized void startWriting() {// 开始写
		++writerCount;
		while (dbReading == true || dbWriting == true) {
			try {
				System.out.println("Writer is waiting");
				wait();// 等待读者发出notify
			} catch (Exception e) {
			}

		}
		dbWriting = true;
	}

	public synchronized void endWriting() {// 结束写
		--writerCount;
		dbWriting = false;
		System.out.println("one writer is done writing. Count=" + writerCount);

		notifyAll();
	}

}

class Reader extends Thread {// 定义读线程，继承Thread类，重写run方法
	private CubbyHole C;
	private int readerNum;

	public Reader(int r, CubbyHole db) {
		readerNum = r;
		C = db;
	}

	public void run() {
		int c;
		while (true) {
			System.out.println("reader " + readerNum + " is sleeping");
			CubbyHole.napping();
			System.out.println("reader " + readerNum + " wants to read");
			c = C.startRead();
			System.out.println("reader " + readerNum + " is reading. Count="
					+ c);
			CubbyHole.napping();
			c = C.endReading();
			System.out.println("It is reader " + readerNum
					+ " who has done reading. count=" + c);

		}
	}
}

class Writer extends Thread {// 定义写线程
	private CubbyHole C;
	private int writerNum;

	public Writer(int w, CubbyHole db) {
		writerNum = w;
		C = db;

	}

	public void run() {
		while (true) {

			System.out.println("Writer " + writerNum + " is sleeping");
			CubbyHole.napping();
			System.out.println("Writer " + writerNum + " wants to write");
			C.startWriting();
			System.out.println("Writer " + writerNum + " is writing");
			CubbyHole.napping();
			C.endWriting();
			System.out.println("It is Writer " + writerNum
					+ " who has done writing .");

		}

	}
}